#include "component.h"
#include "qdebug.h"

using namespace std;

int getH264Subformat(FERange range, void *context, FEList *subs);

static FEFormat format_h264 = {0, getH264Subformat};
FEFormat *get_format() {
    return &format_h264;
}

int getH264Subformat(FERange range, void *context, FEList *subs) {
    return 0;
}

#define BIT_OF(byte) ((byte) << 3)
#define BYTE_OF(bit) ((bit) >> 3)

struct BitStream {
    FERange *range;
    uint64_t bit_current;
    uint64_t bit_remain;
    uint8_t depth;
};

int initBitStream(BitStream *stream, FERange *range){
    stream->range = range;
    stream->bit_current = 0;
    stream->bit_remain = remainFERange(range, stream->bit_current);
    stream->depth = 0;
    return 0;
}

int pushBitStream(BitStream *stream){
    stream->depth++;
    return 0;
}

int popBitStream(BitStream *stream){
    stream->depth--;
    return 0;
}

uint32_t skipBitStream(BitStream *stream, uint8_t bit_size) {
    stream->bit_current += bit_size;
    stream->bit_remain -= bit_size;
    return 0;
}

uint64_t offsetBitStream(BitStream *stream){
    return stream->bit_current;
}

bool more_rbsp_data(BitStream *stream){
    return stream->bit_remain > 0;
}

FEFieldNode *cutDescriptor_align(BitStream *stream, FEField *field, FEList *nodes){
    uint8_t bit_first;
    fetchFERange(stream->range, stream->bit_current, 1, &bit_first);
    if (bit_first == 0) return nullptr;

    FERange sub;
    subFERange(stream->range, &sub, stream->bit_current, 8 - bit_first);
    stream->bit_current += 8 - bit_first;
    stream->bit_remain -= 8 - bit_first;
    auto node = allocFENode(nodes, field, sub);
    depthFENode(node, stream->depth);
    return node;
}

FEFieldNode *cutDescriptor_u(BitStream *stream, uint8_t bit_size, FEField *field, FEList *nodes) {
    uint8_t bit_first;
    uint32_t value = 0;
    FERange sub;
    char *data = fetchFERange(stream->range, stream->bit_current, bit_size, &bit_first);
    bit_size = decodeFEDataFU(data, bit_first, bit_size, &value);
    subFERange(stream->range, &sub, stream->bit_current, bit_size);
    stream->bit_current += bit_size;
    stream->bit_remain -= bit_size;
    auto node = allocFENode(nodes, field, sub);
    depthFENode(node, stream->depth);
    translateFENodeUInt(node, value);
    return node;
}

FEFieldNode *cutDescriptor_ue(BitStream *stream, FEField *field, FEList *nodes){
    uint8_t bit_first;
    uint8_t bit_size;
    uint32_t value = 0;
    FERange sub;
    char *data = fetchFERange(stream->range, stream->bit_current, stream->bit_remain, &bit_first);
    bit_size = decodeFEDataVU(data, bit_first, stream->bit_remain, FECodeGolomb, &value);
    subFERange(stream->range, &sub, stream->bit_current, bit_size);
    stream->bit_current += bit_size;
    stream->bit_remain -= bit_size;
    auto node = allocFENode(nodes, field, sub);
    depthFENode(node, stream->depth);
    translateFENodeUInt(node, value);
    return node;
}

FEFieldNode *cutDescriptor_se(BitStream *stream, FEField *field, FEList *nodes){
    uint8_t bit_first;
    uint8_t bit_size;
    int32_t value = 0;
    FERange sub;
    char *data = fetchFERange(stream->range, stream->bit_current, stream->bit_remain, &bit_first);
    bit_size = decodeFEDataVS(data, bit_first, stream->bit_remain, FECodeGolomb, &value);
    subFERange(stream->range, &sub, stream->bit_current, bit_size);
    stream->bit_current += bit_size;
    stream->bit_remain -= bit_size;
    auto node = allocFENode(nodes, field, sub);
    depthFENode(node, stream->depth);
    translateFENodeInt(node, value);
    return node;
}

struct ContextSPS {
    //element
    uint32_t chroma_format_idc{0};
    uint8_t separate_colour_plane_flag{0};
    uint8_t log2_max_frame_num_minus4{0};
    uint8_t frame_mbs_only_flag{0};
    uint8_t pic_order_cnt_type{0};
    uint8_t log2_max_pic_order_cnt_lsb_minus4{0};
    uint8_t delta_pic_order_always_zero_flag{0};
    uint32_t pic_width_in_mbs_minus1{0};
    uint32_t pic_height_in_map_units_minus1{0};
    uint8_t mb_adaptive_frame_field_flag{0};

    //var
    uint32_t PicWidthInMbs{1};
    uint32_t PicHeightInMapUnits{1};
    uint32_t PicSizeInMapUnits{1};
    uint8_t ChromaArrayType{0};
    uint32_t FrameHeightInMbs{0};
};

struct ContextPPS {
    //element
    uint8_t seq_parameter_set_id{0};
    uint8_t entropy_coding_mode_flag{0};
    uint8_t bottom_field_pic_order_in_frame_present_flag{0};
    uint8_t redundant_pic_cnt_present_flag{0};
    uint8_t weighted_pred_flag{0};
    uint8_t weighted_bipred_idc{0};
    uint8_t deblocking_filter_control_present_flag{0};
    uint32_t num_slice_groups_minus1{0};
    uint8_t slice_group_map_type{0};
    uint8_t slice_group_change_direction_flag{0};
    uint32_t slice_group_change_rate_minus1{0};
    uint16_t *run_length_minus1{nullptr};
    uint16_t *top_left{nullptr};
    uint16_t *bottom_right{nullptr};
    uint16_t *slice_group_id{nullptr};

    //var
    uint32_t SliceGroupChangeRate{1};
};

struct ContextH264 {
    map<uint8_t, ContextSPS *> sps;
    map<uint8_t, ContextPPS *> pps;
};

void freeContextH264(void *context) {
    auto context_h264 = (ContextH264 *)context;

    pair<uint8_t, ContextSPS *> sps;
    foreach (sps, context_h264->sps)
        delete sps.second;

    pair<uint8_t, ContextPPS *> pps;
    foreach (pps, context_h264->pps)
        delete pps.second;

    delete context_h264;
}

struct ContextSlice {
    ContextH264 *h264{nullptr};

    //element
    uint8_t nal_ref_idc{0};
    uint8_t nal_unit_type{0};
    uint8_t pic_parameter_set_id{0};
    uint8_t slice_type{0};
    uint32_t num_ref_idx_l0_active_minus1{0};
    uint32_t num_ref_idx_l1_active_minus1{0};
    uint32_t first_mb_in_slice{0};
    uint8_t field_pic_flag{0};
    uint32_t slice_group_change_cycle{0};

    //var
    uint32_t PicHeightInMbs{0};
    uint32_t PicSizeInMbs{0};
    uint32_t MbaffFrameFlag{0};
    uint32_t MapUnitsInSliceGroup0{0};
    uint32_t sizeOfUpperLeftGroup{0};
    uint16_t *mapUnitToSliceGroupMap{nullptr};
    uint16_t *MbToSliceGroupMap{nullptr};
};

void freeContextSlice(void *context) {
    auto context_slice = (ContextSlice *)context;
    delete context_slice;
}

int64_t dissect_vui_parameters(BitStream *stream, void *context, FEList *nodes);

int64_t dissectH264(FERange range, void *context, FEList *nodes);
int64_t dissectNALU(FERange range, void *context, FEList *nodes);
int64_t dissectSps(FERange range, void *context, FEList *nodes);
int64_t dissect_seq_parameter_set_rbsp(FERange range, void *context, FEList *nodes);
int64_t dissectPps(FERange range, void *context, FEList *nodes);
int64_t dissect_pic_parameter_set_rbsp(FERange range, void *context, FEList *nodes);
int64_t dissectSlice(FERange range, void *context, FEList *nodes);
int64_t dissect_slice_layer_without_partitioning_rbsp(FERange range, void *context, FEList *nodes);
int64_t dissect_slice_header(FERange range, void *context, FEList *nodes);
int64_t dissect_slice_data(FERange range, void *context, FEList *nodes);

int display_slice_type(FEFieldNode *node, char *string, int len);

static FEField field_h264 = {"H264", 0, false, dissectH264, nullptr};

//nalu
static FEField field_nalu_sps = {"Sequence parameter set", sizeof(ContextH264), true, dissectSps, nullptr};
static FEField field_nalu_pps = {"Picture parameter set", sizeof(ContextH264), true, dissectPps, nullptr};
static FEField field_nalu_idr = {"Slice of an IDR picture", sizeof(ContextH264), false, dissectSlice, nullptr};
static FEField field_nalu_slice = {"Slice of a non-IDR picture", sizeof(ContextH264), false, dissectSlice, nullptr};
static FEField field_nalu_slicea = {"Slice data partition A", sizeof(ContextH264), false, dissectNALU, nullptr};
static FEField field_nalu_sliceb = {"Slice data partition B", sizeof(ContextH264), false, dissectNALU, nullptr};
static FEField field_nalu_slicec = {"Slice data partition C", sizeof(ContextH264), false, dissectNALU, nullptr};
static FEField field_nalu_todo = {"TODO: NAL Unit", 0, false, dissectNALU, nullptr};
//common
static FEField field_rbsp_byte = {"rbsp_byte", 0, false, nullptr, nullptr};
static FEField field_seq_parameter_set_id = {"seq_parameter_set_id", 0, false, nullptr, nullptr};
static FEField field_pic_parameter_set_id = {"pic_parameter_set_id", 0, false, nullptr, nullptr};
static FEField field_forbidden_zero_bit = {"forbidden_zero_bit", 0, false, nullptr, nullptr};
static FEField field_nal_ref_idc = {"nal_ref_idc", 0, false, nullptr, nullptr};
static FEField field_nal_unit_type = {"nal_unit_type", 0, false, nullptr, nullptr};
static FEField field_rbsp_stop_one_bit = {"rbsp_stop_one_bit", 0, false, nullptr, nullptr};
static FEField field_rbsp_alignment_zero_bit = {"rbsp_alignment_zero_bit", 0, false, nullptr, nullptr};
//sps
static FEField field_seq_parameter_set_rbsp = {"seq_parameter_set_rbsp()", sizeof(ContextH264), true, dissect_seq_parameter_set_rbsp, nullptr};
static FEField field_profile_idc = {"profile_idc", 0, false, nullptr, displayHex};
static FEField field_constraint_set0_flag = {"constraint_set0_flag", 0, false, nullptr, displayBool};
static FEField field_constraint_set1_flag = {"constraint_set1_flag", 0, false, nullptr, displayBool};
static FEField field_constraint_set2_flag = {"constraint_set2_flag", 0, false, nullptr, displayBool};
static FEField field_constraint_set3_flag = {"constraint_set3_flag", 0, false, nullptr, displayBool};
static FEField field_constraint_set4_flag = {"constraint_set4_flag", 0, false, nullptr, displayBool};
static FEField field_constraint_set5_flag = {"constraint_set5_flag", 0, false, nullptr, displayBool};
static FEField field_reserved_zero_2bits = {"reserved_zero_2bits", 0, false, nullptr, nullptr};
static FEField field_level_idc = {"level_idc", 0, false, nullptr, displayHex};
static FEField field_chroma_format_idc = {"chroma_format_idc", 0, false, nullptr, nullptr};
static FEField field_separate_colour_plane_flag = {"separate_colour_plane_flag", 0, false, nullptr, nullptr};
static FEField field_bit_depth_luma_minus8 = {"bit_depth_luma_minus8", 0, false, nullptr, nullptr};
static FEField field_bit_depth_chroma_minus8 = {"bit_depth_chroma_minus8", 0, false, nullptr, nullptr};
static FEField field_qpprime_y_zero_transform_bypass_flag = {"qpprime_y_zero_transform_bypass_flag", 0, false, nullptr, nullptr};
static FEField field_seq_scaling_matrix_present_flag = {"seq_scaling_matrix_present_flag", 0, false, nullptr, nullptr};
static FEField field_seq_scaling_list_present_flag = {"seq_scaling_list_present_flag", 0, false, nullptr, nullptr};
static FEField field_log2_max_frame_num_minus4 = {"log2_max_frame_num_minus4", 0, false, nullptr, nullptr};
static FEField field_pic_order_cnt_type = {"pic_order_cnt_type", 0, false, nullptr, nullptr};
static FEField field_log2_max_pic_order_cnt_lsb_minus4 = {"log2_max_pic_order_cnt_lsb_minus4", 0, false, nullptr, nullptr};
static FEField field_delta_pic_order_always_zero_flag = {"delta_pic_order_always_zero_flag", 0, false, nullptr, displayBool};
static FEField field_offset_for_non_ref_pic = {"offset_for_non_ref_pic", 0, false, nullptr, nullptr};
static FEField field_offset_for_top_to_bottom_field = {"offset_for_top_to_bottom_field", 0, false, nullptr, nullptr};
static FEField field_num_ref_frames_in_pic_order_cnt_cycle = {"num_ref_frames_in_pic_order_cnt_cycle", 0, false, nullptr, nullptr};
static FEField field_offset_for_ref_frame = {"num_ref_frames_in_pic_order_cnt_cycle", 0, false, nullptr, nullptr};
static FEField field_max_num_ref_frames = {"max_num_ref_frames", 0, false, nullptr, nullptr};
static FEField field_gaps_in_frame_num_value_allowed_flag = {"graps_in_frame_num_value_allowed_flag", 0, false, nullptr, displayBool};
static FEField field_pic_width_in_mbs_minus1 = {"pic_width_in_mbs_minus1", 0, false, nullptr, nullptr};
static FEField field_pic_height_in_map_units_minus1 = {"pic_height_in_map_units_minus1", 0, false, nullptr, nullptr};
static FEField field_frame_mbs_only_flag = {"frame_mbs_only_flag", 0, false, nullptr, displayBool};
static FEField field_mb_adaptive_frame_field_flag = {"mb_adaptive_frame_field_flag", 0, false, nullptr, displayBool};
static FEField field_direct_8x8_inference_flag = {"direct_8x8_inference_flag", 0, false, nullptr, displayBool};
static FEField field_frame_cropping_flag = {"frame_cropping_flag", 0, false, nullptr, displayBool};
static FEField field_frame_crop_left_offset = {"frame_crop_left_offset", 0, false, nullptr, nullptr};
static FEField field_frame_crop_right_offset = {"frame_crop_right_offset", 0, false, nullptr, nullptr};
static FEField field_frame_crop_top_offset = {"frame_crop_top_offset", 0, false, nullptr, nullptr};
static FEField field_frame_crop_bottom_offset = {"frame_crop_bottom_offset", 0, false, nullptr, nullptr};
static FEField field_vui_parameters_present_flag = {"vui_parameters_present_flag", 0, false, nullptr, displayBool};

static FEField field_vui_parameters = {"vui_parameters()", 0, false, nullptr, nullptr};
static FEField field_aspect_ratio_info_present_flag = {"aspect_ratio_info_present_flag", 0, false, nullptr, nullptr};
static FEField field_aspect_ratio_idc = {"aspect_ratio_idc", 0, false, nullptr, nullptr};
static FEField field_sar_width = {"sar_width", 0, false, nullptr, nullptr};
static FEField field_sar_height = {"sar_height", 0, false, nullptr, nullptr};
static FEField field_overscan_info_present_flag = {"overscan_info_present_flag", 0, false, nullptr, nullptr};
static FEField field_overscan_appropriate_flag = {"overscan_appropriate_flag", 0, false, nullptr, nullptr};
static FEField field_video_signal_type_present_flag = {"video_signal_type_present_flag", 0, false, nullptr, nullptr};
static FEField field_video_format = {"video_format", 0, false, nullptr, nullptr};
static FEField field_video_full_range_flag = {"video_full_range_flag", 0, false, nullptr, nullptr};
static FEField field_colour_description_present_flag = {"colour_description_present_flag", 0, false, nullptr, nullptr};
static FEField field_colour_primaries = {"colour_primaries", 0, false, nullptr, nullptr};
static FEField field_transfer_characteristics = {"transfer_characteristics", 0, false, nullptr, nullptr};
static FEField field_matrix_coefficients = {"matrix_coefficients", 0, false, nullptr, nullptr};
static FEField field_chroma_loc_info_present_flag = {"chroma_loc_info_present_flag", 0, false, nullptr, nullptr};
static FEField field_chroma_sample_loc_type_top_field = {"chroma_sample_loc_type_top_field", 0, false, nullptr, nullptr};
static FEField field_chroma_sample_loc_type_bottom_field = {"chroma_sample_loc_type_bottom_field", 0, false, nullptr, nullptr};
static FEField field_timing_info_present_flag = {"timing_info_present_flag", 0, false, nullptr, nullptr};
static FEField field_num_units_in_tick = {"num_units_in_tick", 0, false, nullptr, nullptr};
static FEField field_time_scale = {"time_scale", 0, false, nullptr, nullptr};
static FEField field_fixed_frame_rate_flag = {"fixed_frame_rate_flag", 0, false, nullptr, nullptr};
static FEField field_nal_hrd_parameters_present_flag = {"nal_hrd_parameters_present_flag", 0, false, nullptr, nullptr};
static FEField field_vcl_hrd_parameters_present_flag = {"vcl_hrd_parameters_present_flag", 0, false, nullptr, nullptr};
static FEField field_low_delay_hrd_flag = {"vcl_low_delay_hrd_flag", 0, false, nullptr, nullptr};
static FEField field_pic_struct_present_flag = {"pic_struct_present_flag", 0, false, nullptr, nullptr};
static FEField field_bitstream_restriction_flag = {"bitstream_restriction_flag", 0, false, nullptr, nullptr};
static FEField field_motion_vectors_over_pic_boundaries_flag = {"motion_vectors_over_pic_boundaries_flag", 0, false, nullptr, nullptr};
static FEField field_max_bytes_per_pic_denom = {"max_bytes_per_pic_denom", 0, false, nullptr, nullptr};
static FEField field_max_bits_per_mb_denom = {"max_bits_per_mb_denom", 0, false, nullptr, nullptr};
static FEField field_log2_max_mv_length_horizontal = {"log2_max_mv_length_horizontal", 0, false, nullptr, nullptr};
static FEField field_log2_max_mv_length_vertical = {"log2_max_mv_length_vertical", 0, false, nullptr, nullptr};
static FEField field_max_num_reorder_frames = {"max_num_reorder_frames", 0, false, nullptr, nullptr};
static FEField field_max_dec_frame_buffering = {"max_dec_frame_buffering", 0, false, nullptr, nullptr};

static FEField field_hrd_parameters = {"hrd_parameters()", 0, false, nullptr, nullptr};
static FEField field_cpb_cnt_minus1 = {"cpb_cnt_minus1", 0, false, nullptr, nullptr};
static FEField field_bit_rate_scale = {"bit_rate_scale", 0, false, nullptr, nullptr};
static FEField field_cpb_size_scale = {"cpb_size_scale", 0, false, nullptr, nullptr};
static FEField field_bit_rate_value_minus1 = {"bit_rate_value_minus1", 0, false, nullptr, nullptr};
static FEField field_cpb_size_value_minus1 = {"cpb_size_value_minus1", 0, false, nullptr, nullptr};
static FEField field_cbr_flag = {"cbr_flag", 0, false, nullptr, nullptr};
static FEField field_initial_cpb_removal_delay_length_minus1 = {"initial_cpb_removal_delay_length_minus1", 0, false, nullptr, nullptr};
static FEField field_cpb_removal_delay_length_minus1 = {"cpb_removal_delay_length_minus1", 0, false, nullptr, nullptr};
static FEField field_dpb_output_delay_length_minus1 = {"dpb_output_delay_length_minus1", 0, false, nullptr, nullptr};
static FEField field_time_offset_length = {"time_offset_length", 0, false, nullptr, nullptr};

//pps
static FEField field_pic_parameter_set_rbsp = {"pic_parameter_set_rbsp()", sizeof(ContextH264), true, dissect_pic_parameter_set_rbsp, nullptr};
static FEField field_entropy_coding_mode_flag = {"entropy_coding_mode_flag", 0, false, nullptr, nullptr};
static FEField field_bottom_field_pic_order_in_frame_present_flag = {"bottom_field_pic_order_in_frame_present_flag", 0, false, nullptr, nullptr};
static FEField field_num_slice_groups_minus1 = {"num_slice_groups_minus1", 0, false, nullptr, nullptr};
static FEField field_slice_group_map_type = {"slice_group_map_type", 0, false, nullptr, nullptr};
static FEField field_run_length_minus1 = {"run_length_minus1", 0, false, nullptr, nullptr};
static FEField field_top_left = {"top_left", 0, false, nullptr, nullptr};
static FEField field_bottom_right = {"bottom_right", 0, false, nullptr, nullptr};
static FEField field_slice_group_change_direction_flag = {"slice_group_change_direction_flag", 0, false, nullptr, nullptr};
static FEField field_slice_group_change_rate_minus1 = {"slice_group_change_rate_minus1", 0, false, nullptr, nullptr};
static FEField field_pic_size_in_map_units_minus1 = {"pic_size_in_map_units_minus1", 0, false, nullptr, nullptr};
static FEField field_slice_group_id = {"slice_group_id", 0, false, nullptr, nullptr};
static FEField field_num_ref_idx_l0_default_active_minus1 = {"num_ref_idx_l0_default_active_minus1", 0, false, nullptr, nullptr};
static FEField field_num_ref_idx_l1_default_active_minus1 = {"num_ref_idx_l1_default_active_minus1", 0, false, nullptr, nullptr};
static FEField field_weighted_pred_flag = {"weighted_pred_flag", 0, false, nullptr, nullptr};
static FEField field_weighted_bipred_idc = {"weighted_bipred_idc", 0, false, nullptr, nullptr};
static FEField field_pic_init_qp_minus26 = {"pic_init_qp_minus26", 0, false, nullptr, nullptr};
static FEField field_pic_init_qs_minus26 = {"pic_init_qs_minus26", 0, false, nullptr, nullptr};
static FEField field_chroma_qp_index_offset = {"chroma_qp_index_offset", 0, false, nullptr, nullptr};
static FEField field_deblocking_filter_control_present_flag = {"deblocking_filter_control_present_flag", 0, false, nullptr, nullptr};
static FEField field_constrained_intra_pred_flag = {"constrained_intra_pred_flag", 0, false, nullptr, nullptr};
static FEField field_redundant_pic_cnt_present_flag = {"redundant_pic_cnt_present_flag", 0, false, nullptr, nullptr};
static FEField field_transform_8x8_mode_flag = {"transform_8x8_mode_flag", 0, false, nullptr, nullptr};
static FEField field_pic_scaling_matrix_present_flag = {"pic_scaling_matrix_present_flag", 0, false, nullptr, nullptr};
static FEField field_pic_scaling_list_present_flag = {"pic_scaling_list_present_flag", 0, false, nullptr, nullptr};
static FEField field_second_chroma_qp_index_offset = {"second_chroma_qp_index_offset", 0, false, nullptr, nullptr};
//slice
static FEField field_slice_layer_without_partitioning_rbsp = {"slice_layer_without_partitioning_rbsp()", sizeof(ContextH264), false, dissect_slice_layer_without_partitioning_rbsp, nullptr};

static FEField field_slice_header = {"slice_header()", sizeof(ContextSlice), true, dissect_slice_header, nullptr};
static FEField field_first_mb_in_slice = {"first_mb_in_slice", 0, false, nullptr, nullptr};
static FEField field_slice_type = {"slice_type", 0, false, nullptr, display_slice_type};
static FEField field_colour_plane_id = {"colour_plane_id", 0, false, nullptr, nullptr};
static FEField field_frame_num = {"frame_num", 0, false, nullptr, nullptr};
static FEField field_field_pic_flag = {"field_pic_flag", 0, false, nullptr, nullptr};
static FEField field_bottom_field_flag = {"bottom_field_flag", 0, false, nullptr, nullptr};
static FEField field_idr_pic_id = {"idr_pic_id", 0, false, nullptr, nullptr};
static FEField field_pic_order_cnt_lsb = {"pic_order_cnt_lsb", 0, false, nullptr, nullptr};
static FEField field_delta_pic_order_cnt_bottom = {"delta_pic_order_cnt_bottom", 0, false, nullptr, nullptr};
static FEField field_delta_pic_order_cnt = {"delta_pic_order_cnt", 0, false, nullptr, nullptr};
static FEField field_redundant_pic_cnt = {"redundant_pic_cnt", 0, false, nullptr, nullptr};
static FEField field_direct_spatial_mv_pred_flag = {"direct_spatial_mv_pred_flag", 0, false, nullptr, nullptr};
static FEField field_num_ref_idx_active_override_flag = {"num_ref_idx_active_override_flag", 0, false, nullptr, nullptr};
static FEField field_num_ref_idx_l0_active_minus1 = {"num_ref_idx_l0_active_minus1", 0, false, nullptr, nullptr};
static FEField field_num_ref_idx_l1_active_minus1 = {"num_ref_idx_l1_active_minus1", 0, false, nullptr, nullptr};
static FEField field_cabac_init_idc = {"cabac_init_idc", 0, false, nullptr, nullptr};
static FEField field_slice_qp_delta = {"slice_qp_delta", 0, false, nullptr, nullptr};
static FEField field_sp_for_switch_flag = {"sp_for_switch_flag", 0, false, nullptr, nullptr};
static FEField field_slice_qs_delta = {"slice_qs_delta", 0, false, nullptr, nullptr};
static FEField field_disable_deblocking_filter_idc = {"disable_deblocking_filter_idc", 0, false, nullptr, nullptr};
static FEField field_slice_alpha_c0_offset_div2 = {"slice_alpha_c0_offset_div2", 0, false, nullptr, nullptr};
static FEField field_slice_beta_offset_div2 = {"slice_beta_offset_div2", 0, false, nullptr, nullptr};
static FEField field_slice_group_change_cycle = {"slice_group_change_cycle", 0, false, nullptr, nullptr};

static FEField field_ref_pic_list_mvc_modification = {"ref_pic_list_mvc_modification()", 0, false, nullptr, nullptr};

static FEField field_ref_pic_list_modification = {"ref_pic_list_modification()", 0, false, nullptr, nullptr};
static FEField field_ref_pic_list_modification_flag_l0 = {"ref_pic_list_modification_flag_l0", 0, false, nullptr, nullptr};
static FEField field_modification_of_pic_nums_idc = {"modification_of_pic_nums_idc", 0, false, nullptr, nullptr};
static FEField field_abs_diff_pic_num_minus1 = {"abs_diff_pic_num_minus1", 0, false, nullptr, nullptr};
static FEField field_long_term_pic_num = {"long_term_pic_num", 0, false, nullptr, nullptr};
static FEField field_ref_pic_list_modification_flag_l1 = {"ref_pic_list_modification_flag_l1", 0, false, nullptr, nullptr};

static FEField field_pred_weight_table = {"pred_weight_table()", 0, false, nullptr, nullptr};
static FEField field_luma_log2_weight_denom = {"luma_log2_weight_denom", 0, false, nullptr, nullptr};
static FEField field_chroma_log2_weight_denom = {"chroma_log2_weight_denom", 0, false, nullptr, nullptr};
static FEField field_luma_weight_l0_flag = {"luma_weight_l0_flag", 0, false, nullptr, nullptr};
static FEField field_luma_weight_l0 = {"luma_weight_l0", 0, false, nullptr, nullptr};
static FEField field_luma_offset_l0 = {"luma_offset_l0", 0, false, nullptr, nullptr};
static FEField field_chroma_weight_l0_flag = {"chroma_weight_l0_flag", 0, false, nullptr, nullptr};
static FEField field_chroma_weight_l0 = {"chroma_weight_l0", 0, false, nullptr, nullptr};
static FEField field_chroma_offset_l0 = {"chroma_offset_l0", 0, false, nullptr, nullptr};
static FEField field_luma_weight_l1_flag = {"luma_weight_l1_flag", 0, false, nullptr, nullptr};
static FEField field_luma_weight_l1 = {"luma_weight_l1", 0, false, nullptr, nullptr};
static FEField field_luma_offset_l1 = {"luma_offset_l1", 0, false, nullptr, nullptr};
static FEField field_chroma_weight_l1_flag = {"chroma_weight_l1_flag", 0, false, nullptr, nullptr};
static FEField field_chroma_weight_l1 = {"chroma_weight_l1", 0, false, nullptr, nullptr};
static FEField field_chroma_offset_l1 = {"chroma_offset_l1", 0, false, nullptr, nullptr};

static FEField field_dec_ref_pic_marking = {"dec_ref_pic_marking()", 0, false, nullptr, nullptr};
static FEField field_no_output_of_prior_pics_flag = {"no_output_of_prior_pics_flag", 0, false, nullptr, nullptr};
static FEField field_long_term_reference_flag = {"long_term_reference_flag", 0, false, nullptr, nullptr};
static FEField field_adaptive_ref_pic_marking_mode_flag = {"adaptive_ref_pic_marking_mode_flag", 0, false, nullptr, nullptr};
static FEField field_memory_management_control_operation = {"memory_management_control_operation", 0, false, nullptr, nullptr};
static FEField field_difference_of_pic_nums_minus1 = {"difference_of_pic_nums_minus1", 0, false, nullptr, nullptr};
static FEField field_long_term_frame_idx = {"long_term_frame_idx", 0, false, nullptr, nullptr};
static FEField field_max_long_term_frame_idx_plus1 = {"max_long_term_frame_idx_plus1", 0, false, nullptr, nullptr};

static FEField field_slice_data = {"slice_data()", sizeof(ContextSlice), false, nullptr, nullptr};
static FEField field_cabac_alignment_one_bit = {"cabac_alignment_one_bit", 0, false, nullptr, nullptr};
static FEField field_mb_skip_run = {"mb_skip_run", 0, false, nullptr, nullptr};
static FEField field_mb_skip_flag = {"mb_skip_flag", 0, false, nullptr, nullptr};
static FEField field_mb_field_decoding_flag = {"mb_field_decoding_flag", 0, false, nullptr, nullptr};
static FEField field_end_of_slice_flag = {"end_of_slice_flag", 0, false, nullptr, nullptr};

FEField *get_top_field(){
    return &field_h264;
}

FEField *naluField(int value) {
    switch(value) {
    case 1:
        return &field_nalu_slice;
    case 2:
        return &field_nalu_slicea;
    case 3:
        return &field_nalu_sliceb;
    case 4:
        return &field_nalu_slicec;
    case 5:
        return &field_nalu_idr;
    case 7:
        return &field_nalu_sps;
    case 8:
        return &field_nalu_pps;
    default:
        return &field_nalu_todo;
    }
}

int64_t dissectH264(FERange range, void *context, FEList *nodes) {
    int nal_unit_type;
    auto context_h264 = new ContextH264();
    FEFieldNode *node;

    char state = 4;
    int64_t nalu_head = -1;
    FERange nalu_range;
    uint64_t offset = 0;
    uint64_t len = remainFERangeByte(&range, offset);
    if (len > 1024) len = 1024;
    while (len) {
        auto data = fetchFERangeByte(&range, offset, len);
        char *pos = data;
        char *end = data + len;
        while (pos < end)
        {
            if ((pos - data + offset) == nalu_head) {
                nal_unit_type = *pos & 0x1f;
            }

            if(!*pos) {
                state >>= 1;
            } else if ((state == 0 || state == 1) && *pos == 1) {
                uint64_t new_head = pos - data + offset + 1;
                if (nalu_head == -1) {
                    nalu_head = new_head;
                } else {
                    subFERangeByte(&range, &nalu_range, nalu_head, new_head - nalu_head - 4 + state);
                    node = allocFENode(nodes, naluField(nal_unit_type), nalu_range);
                    contextFENode(node, context_h264, nullptr);
                    nalu_head = new_head;
                }
            } else {
                state = 4;
            }
            pos++;
        }

        //next round
        offset += len;
        len = remainFERangeByte(&range, offset);
        if (len > 1024) len = 1024;
    }

//    qDebug() << "dissectH264 offset:" << offset << " len:" << len;
    subFERangeByte(&range, &nalu_range, nalu_head, offset - nalu_head);
    node = allocFENode(nodes, naluField(nal_unit_type), nalu_range);
    contextFENode(node, context_h264, freeContextH264);
    return range.bit_len;
}

bool needEscape(char *data, int len) {
    char state = 2;
    char *s = data;
    char *e = data + len;

    while(s != e) {
        if(*s == 0)
            state >>= 1;
        else if(state == 0 && *s == 3)
            return true;
        else
            state = 2;
        s++;
    }

    return false;
}

int getRBSP(char *data, char *rbsp, int len) {
    char state = 2;
    char *s = data;
    char *d = rbsp;
    while(s != data + len) {
        if (*s == 0) {
            state >>= 1;
            *d = *s;
            d++;
        } else if(state == 0 && *s == 3) {
            state = 2;
        } else {
            state = 2;
            *d = *s;
            d++;
        }

        s++;
    }
    return d - rbsp;
}

int64_t dissectNALU(FERange range, void *context, FEList *nodes){
    BitStream stream;
    initBitStream(&stream, &range);

    cutDescriptor_u(&stream, 1, &field_forbidden_zero_bit, nodes);
    cutDescriptor_u(&stream, 2, &field_nal_ref_idc, nodes);
    cutDescriptor_u(&stream, 5, &field_nal_unit_type, nodes);

    FERange sub;
    subFERangeByte(&range, &sub, 1, remainFERangeByte(&range, 1));
    allocFENode(nodes, &field_rbsp_byte, sub);
    return range.bit_len;
}

int64_t dissectSps(FERange range, void *context, FEList *nodes) {
    BitStream stream;
    initBitStream(&stream, &range);

    cutDescriptor_u(&stream, 1, &field_forbidden_zero_bit, nodes);
    cutDescriptor_u(&stream, 2, &field_nal_ref_idc, nodes);
    cutDescriptor_u(&stream, 5, &field_nal_unit_type, nodes);

    uint64_t len = remainFERangeByte(&range, 1);
    auto data = fetchFERangeByte(&range, 1, len);
    if (!data) return -1;

    FEFieldNode *node;
    FERange sub;
    subFERangeByte(&range, &sub, 1, len);
    node = allocFENode(nodes, &field_seq_parameter_set_rbsp, sub);
    contextFENode(node, context, nullptr);
    auto escaped = needEscape(data, len);
    if (escaped) {
        char *rbsp = (char *)malloc(len);
        int rbsp_len = getRBSP(data, rbsp, len);
        translateFENodeText(node, rbsp, rbsp_len);
    }
    return range.bit_len;
}

int64_t dissect_hrd_parameters(BitStream *stream, void *context, FEList *nodes){
    FEFieldNode *node;
    node = cutDescriptor_ue(stream, &field_cpb_cnt_minus1, nodes);
    uint32_t cpb_cnt_minus1 = node->translation.ui;
    cutDescriptor_u(stream, 4, &field_bit_rate_scale, nodes);
    cutDescriptor_u(stream, 4, &field_cpb_size_scale, nodes);
    for(uint32_t SchedSelIdx = 0; SchedSelIdx <= cpb_cnt_minus1; SchedSelIdx++ ){
        node = cutDescriptor_ue(stream, &field_bit_rate_value_minus1, nodes);
        indexFENode(node, SchedSelIdx, -1, -1);
        node = cutDescriptor_ue(stream, &field_cpb_size_value_minus1, nodes);
        indexFENode(node, SchedSelIdx, -1, -1);
        node = cutDescriptor_u(stream, 1, &field_cbr_flag, nodes);
        indexFENode(node, SchedSelIdx, -1, -1);
    }

    cutDescriptor_u(stream, 5, &field_initial_cpb_removal_delay_length_minus1, nodes);
    cutDescriptor_u(stream, 5, &field_cpb_removal_delay_length_minus1, nodes);
    cutDescriptor_u(stream, 5, &field_dpb_output_delay_length_minus1, nodes);
    cutDescriptor_u(stream, 5, &field_time_offset_length, nodes);
    return 0;
}

int64_t dissect_vui_parameters(BitStream *stream, void *context, FEList *nodes){
    FEFieldNode *node;
    node = cutDescriptor_u(stream, 1, &field_aspect_ratio_info_present_flag, nodes);
    uint8_t aspect_ratio_info_present_flag = node->translation.ui;
    if (aspect_ratio_info_present_flag) {
        node = cutDescriptor_u(stream, 8, &field_aspect_ratio_idc, nodes);
        uint8_t aspect_ratio_idc = node->translation.ui;
        if (aspect_ratio_idc == 255) { //Extended_SAR
            cutDescriptor_u(stream, 16, &field_sar_width, nodes);
            cutDescriptor_u(stream, 16, &field_sar_height, nodes);
        }
    }

    node = cutDescriptor_u(stream, 1, &field_overscan_info_present_flag, nodes);
    uint8_t overscan_info_present_flag = node->translation.ui;
    if (overscan_info_present_flag)
        cutDescriptor_u(stream, 1, &field_overscan_appropriate_flag, nodes);

    node = cutDescriptor_u(stream, 1, &field_video_signal_type_present_flag, nodes);
    uint8_t video_signal_type_present_flag = node->translation.ui;
    if (video_signal_type_present_flag) {
        cutDescriptor_u(stream, 3, &field_video_format, nodes);
        cutDescriptor_u(stream, 1, &field_video_full_range_flag, nodes);
        node = cutDescriptor_u(stream, 1, &field_colour_description_present_flag, nodes);
        uint8_t colour_description_present_flag = node->translation.ui;
        if (colour_description_present_flag) {
            cutDescriptor_u(stream, 8, &field_colour_primaries, nodes);
            cutDescriptor_u(stream, 8, &field_transfer_characteristics, nodes);
            cutDescriptor_u(stream, 8, &field_matrix_coefficients, nodes);
        }
    }

    node = cutDescriptor_u(stream, 1, &field_chroma_loc_info_present_flag, nodes);
    uint8_t chroma_loc_info_present_flag = node->translation.ui;
    if (chroma_loc_info_present_flag) {
        cutDescriptor_ue(stream, &field_chroma_sample_loc_type_top_field, nodes);
        cutDescriptor_ue(stream, &field_chroma_sample_loc_type_bottom_field, nodes);
    }

    node = cutDescriptor_u(stream, 1, &field_timing_info_present_flag, nodes);
    uint8_t timing_info_present_flag = node->translation.ui;
    if (timing_info_present_flag) {
        cutDescriptor_u(stream, 32, &field_num_units_in_tick, nodes);
        cutDescriptor_u(stream, 32, &field_time_scale, nodes);
        cutDescriptor_u(stream, 1, &field_fixed_frame_rate_flag, nodes);
    }

    node = cutDescriptor_u(stream, 1, &field_nal_hrd_parameters_present_flag, nodes);
    uint8_t nal_hrd_parameters_present_flag = node->translation.ui;
    if (nal_hrd_parameters_present_flag) {
        FERange sub;
        subFERange(stream->range, &sub, stream->bit_current, -1);
        allocFENode(nodes, &field_hrd_parameters, sub);
        pushBitStream(stream);
        dissect_hrd_parameters(stream, context, nodes);
        popBitStream(stream);
    }

    node = cutDescriptor_u(stream, 1, &field_vcl_hrd_parameters_present_flag, nodes);
    uint8_t vcl_hrd_parameters_present_flag = node->translation.ui;
    if( vcl_hrd_parameters_present_flag ) {
        FERange sub;
        subFERange(stream->range, &sub, stream->bit_current, -1);
        allocFENode(nodes, &field_hrd_parameters, sub);
        pushBitStream(stream);
        dissect_hrd_parameters(stream, context, nodes);
        popBitStream(stream);
    }

    if (nal_hrd_parameters_present_flag || vcl_hrd_parameters_present_flag)
        cutDescriptor_u(stream, 1, &field_low_delay_hrd_flag, nodes);

    cutDescriptor_u(stream, 1, &field_pic_struct_present_flag, nodes);
    node = cutDescriptor_u(stream, 1, &field_bitstream_restriction_flag, nodes);
    uint8_t bitstream_restriction_flag = node->translation.ui;
    if (bitstream_restriction_flag) {
        cutDescriptor_u(stream, 1, &field_motion_vectors_over_pic_boundaries_flag, nodes);
        cutDescriptor_ue(stream, &field_max_bytes_per_pic_denom, nodes);
        cutDescriptor_ue(stream, &field_max_bits_per_mb_denom, nodes);
        cutDescriptor_ue(stream, &field_log2_max_mv_length_horizontal, nodes);
        cutDescriptor_ue(stream, &field_log2_max_mv_length_vertical, nodes);
        cutDescriptor_ue(stream, &field_max_num_reorder_frames, nodes);
        cutDescriptor_ue(stream, &field_max_dec_frame_buffering, nodes);
    }
    return 0;
}

int64_t dissect_seq_parameter_set_rbsp(FERange range, void *context, FEList *nodes) {
    auto context_h264 = (ContextH264 *)context;
    uint8_t seq_parameter_set_id;
    auto sps = new ContextSPS();

    int64_t bit_len = remainFERange(&range, 0);
    char trail = *fetchFERangeByte(&range, (bit_len >> 3) - 1, 1);
    if (trail == 0) return -1;

    uint32_t trail_bits = log2((uint8_t)(trail & -trail)) + 1;

    FEFieldNode *node;
    BitStream stream;
    FERange range_data;
    subFERange(&range, &range_data, 0, bit_len - trail_bits);
    initBitStream(&stream, &range_data);

    node = cutDescriptor_u(&stream, 8, &field_profile_idc, nodes);
    uint32_t profile_idc = node->translation.ui;
    cutDescriptor_u(&stream, 1, &field_constraint_set0_flag, nodes);
    cutDescriptor_u(&stream, 1, &field_constraint_set1_flag, nodes);
    cutDescriptor_u(&stream, 1, &field_constraint_set2_flag, nodes);
    cutDescriptor_u(&stream, 1, &field_constraint_set3_flag, nodes);
    cutDescriptor_u(&stream, 1, &field_constraint_set4_flag, nodes);
    cutDescriptor_u(&stream, 1, &field_constraint_set5_flag, nodes);
    cutDescriptor_u(&stream, 2, &field_reserved_zero_2bits, nodes);

    cutDescriptor_u(&stream, 8, &field_level_idc, nodes);

    node = cutDescriptor_ue(&stream, &field_seq_parameter_set_id, nodes);
    seq_parameter_set_id = node->translation.ui;

    if (profile_idc == 100
            || profile_idc == 110
            || profile_idc == 122
            || profile_idc == 244
            || profile_idc == 44
            || profile_idc == 83
            || profile_idc == 86
            || profile_idc == 118
            || profile_idc == 128
            || profile_idc == 138
            || profile_idc == 139
            || profile_idc == 134
            || profile_idc == 135 ) {
        node = cutDescriptor_ue(&stream, &field_chroma_format_idc, nodes);
        sps->chroma_format_idc = node->translation.ui;
        if (sps->chroma_format_idc == 3) {
            node = cutDescriptor_u(&stream, 1, &field_separate_colour_plane_flag, nodes);
            sps->separate_colour_plane_flag = node->translation.ui;
        }
        cutDescriptor_ue(&stream, &field_bit_depth_luma_minus8, nodes);
        cutDescriptor_ue(&stream, &field_bit_depth_chroma_minus8, nodes);
        cutDescriptor_u(&stream, 1, &field_qpprime_y_zero_transform_bypass_flag, nodes);
        node = cutDescriptor_u(&stream, 1, &field_seq_scaling_matrix_present_flag, nodes);
        uint32_t seq_scaling_matrix_present_flag = node->translation.ui;
        if (seq_scaling_matrix_present_flag) {
            //todo
        }
    }

    node = cutDescriptor_ue(&stream, &field_log2_max_frame_num_minus4, nodes);
    sps->log2_max_frame_num_minus4 = node->translation.ui;
    node = cutDescriptor_ue(&stream, &field_pic_order_cnt_type, nodes);
    sps->pic_order_cnt_type = node->translation.ui;
    if  (sps->pic_order_cnt_type == 0) {
        node = cutDescriptor_ue(&stream, &field_log2_max_pic_order_cnt_lsb_minus4, nodes);
        sps->log2_max_pic_order_cnt_lsb_minus4 = node->translation.ui;
    } else if (sps->pic_order_cnt_type == 1) {
        node = cutDescriptor_u(&stream, 1, &field_delta_pic_order_always_zero_flag, nodes);
        sps->delta_pic_order_always_zero_flag = node->translation.ui;
        cutDescriptor_se(&stream, &field_offset_for_non_ref_pic, nodes);
        cutDescriptor_se(&stream, &field_offset_for_top_to_bottom_field, nodes);
        node = cutDescriptor_ue(&stream, &field_num_ref_frames_in_pic_order_cnt_cycle, nodes);
        uint32_t num_ref_frames_in_pic_order_cnt_cycle = node->translation.ui;
        for(int i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++){
            node = cutDescriptor_se(&stream, &field_offset_for_ref_frame, nodes);
            indexFENode(node, i, -1, -1);
        }
    }

    cutDescriptor_ue(&stream, &field_max_num_ref_frames, nodes);
    cutDescriptor_u(&stream, 1, &field_gaps_in_frame_num_value_allowed_flag, nodes);
    node = cutDescriptor_ue(&stream, &field_pic_width_in_mbs_minus1, nodes);
    sps->pic_width_in_mbs_minus1 = node->translation.ui;
    node = cutDescriptor_ue(&stream, &field_pic_height_in_map_units_minus1, nodes);
    sps->pic_height_in_map_units_minus1 = node->translation.ui;
    node = cutDescriptor_u(&stream, 1, &field_frame_mbs_only_flag, nodes);
    sps->frame_mbs_only_flag = node->translation.ui;
    if (!sps->frame_mbs_only_flag) {
        node = cutDescriptor_u(&stream, 1, &field_mb_adaptive_frame_field_flag, nodes);
        sps->mb_adaptive_frame_field_flag = node->translation.ui;
    }
    cutDescriptor_u(&stream, 1, &field_direct_8x8_inference_flag, nodes);
    node = cutDescriptor_u(&stream, 1, &field_frame_cropping_flag, nodes);
    uint32_t frame_cropping_flag = node->translation.ui;
    if(frame_cropping_flag) {
        cutDescriptor_ue(&stream, &field_frame_crop_left_offset, nodes);
        cutDescriptor_ue(&stream, &field_frame_crop_right_offset, nodes);
        cutDescriptor_ue(&stream, &field_frame_crop_top_offset, nodes);
        cutDescriptor_ue(&stream, &field_frame_crop_bottom_offset, nodes);
    }

    node = cutDescriptor_u(&stream, 1, &field_vui_parameters_present_flag, nodes);
    uint32_t vui_parameters_present_flag = node->translation.ui;
    if (vui_parameters_present_flag) {
        FERange sub;
        subFERange(stream.range, &sub, stream.bit_current, -1);
        allocFENode(nodes, &field_vui_parameters, sub);
        pushBitStream(&stream);
        dissect_vui_parameters(&stream, sps, nodes);
        popBitStream(&stream);
    }

    FERange range_trail;
    subFERange(&range, &range_trail, bit_len - trail_bits, trail_bits);
    initBitStream(&stream, &range_trail);
    cutDescriptor_u(&stream, 1, &field_rbsp_stop_one_bit, nodes);
    if (trail_bits > 1) {
        cutDescriptor_u(&stream, trail_bits - 1, &field_rbsp_alignment_zero_bit, nodes);
    }

    if (sps->separate_colour_plane_flag == 0)
        sps->ChromaArrayType = sps->chroma_format_idc; //7.4.2.1.1
    sps->PicWidthInMbs = sps->pic_width_in_mbs_minus1 + 1; //(7-13)
    sps->PicHeightInMapUnits = sps->pic_height_in_map_units_minus1 + 1; //(7-16)
    sps->PicSizeInMapUnits = sps->PicWidthInMbs * sps->PicHeightInMapUnits; //(7-17)
    sps->FrameHeightInMbs = (2 - sps->frame_mbs_only_flag) * sps->PicHeightInMapUnits;//(7-18)

    if (context_h264->sps.find(seq_parameter_set_id) != context_h264->sps.end()) {
        delete sps;
    } else {
        context_h264->sps[seq_parameter_set_id] = sps;
    }
    return range.bit_len;
}

int64_t dissectPps(FERange range, void *context, FEList *nodes) {
    BitStream stream;
    initBitStream(&stream, &range);

    cutDescriptor_u(&stream, 1, &field_forbidden_zero_bit, nodes);
    cutDescriptor_u(&stream, 2, &field_nal_ref_idc, nodes);
    cutDescriptor_u(&stream, 5, &field_nal_unit_type, nodes);

    uint64_t len = remainFERangeByte(&range, 1);
    auto data = fetchFERangeByte(&range, 1, len);
    if (!data) return -1;

    FEFieldNode *node;
    FERange sub;
    subFERangeByte(&range, &sub, 1, len);
    node = allocFENode(nodes, &field_pic_parameter_set_rbsp, sub);
    contextFENode(node, context, nullptr);
    auto escaped = needEscape(data, len);
    if (escaped) {
        char *rbsp = (char *)malloc(len);
        int rbsp_len = getRBSP(data, rbsp, len);
        translateFENodeText(node, rbsp, rbsp_len);
    }

    return range.bit_len;
}

int64_t dissect_pic_parameter_set_rbsp(FERange range, void *context, FEList *nodes){
    auto context_h264 = (ContextH264 *)context;
    uint8_t pic_parameter_set_id;
    auto pps = new ContextPPS();

    uint64_t bit_len = remainFERange(&range, 0);
    char trail = *fetchFERangeByte(&range, (bit_len >> 3) - 1, 1);
    if (trail == 0) return -1;

    uint32_t trail_bits = log2((uint8_t)(trail & -trail)) + 1;

    FEFieldNode *node;
    BitStream stream;
    FERange range_data;
    subFERange(&range, &range_data, 0, bit_len - trail_bits);
    initBitStream(&stream, &range_data);

    node = cutDescriptor_ue(&stream, &field_pic_parameter_set_id, nodes);
    pic_parameter_set_id = node->translation.ui;
    node = cutDescriptor_ue(&stream, &field_seq_parameter_set_id, nodes);
    pps->seq_parameter_set_id = node->translation.ui;
    auto sps_it = context_h264->sps.find(pps->seq_parameter_set_id);
    if (sps_it == context_h264->sps.end()) {
        delete pps;
        return 0;
    }

    node = cutDescriptor_u(&stream, 1, &field_entropy_coding_mode_flag, nodes);
    pps->entropy_coding_mode_flag = node->translation.ui;
    node = cutDescriptor_u(&stream, 1, &field_bottom_field_pic_order_in_frame_present_flag, nodes);
    pps->bottom_field_pic_order_in_frame_present_flag = node->translation.ui;

    node = cutDescriptor_ue(&stream, &field_num_slice_groups_minus1, nodes);
    pps->num_slice_groups_minus1 = node->translation.ui;
    if (pps->num_slice_groups_minus1 > 0) {
        node = cutDescriptor_ue(&stream, &field_slice_group_map_type, nodes);
        pps->slice_group_map_type = node->translation.ui;
        if (pps->slice_group_map_type == 0) {
            pps->run_length_minus1 = (uint16_t *)malloc((pps->num_slice_groups_minus1 + 1) * sizeof(uint16_t));
            for (uint32_t iGroup = 0; iGroup <= pps->num_slice_groups_minus1; iGroup++) {
                node = cutDescriptor_ue(&stream, &field_run_length_minus1, nodes);
                indexFENode(node, iGroup, -1, -1);
                pps->run_length_minus1[iGroup] = node->translation.ui;
            }
        } else if (pps->slice_group_map_type == 2) {
            pps->top_left = (uint16_t *)malloc((pps->num_slice_groups_minus1 + 1) * sizeof(uint16_t));
            pps->bottom_right = (uint16_t *)malloc((pps->num_slice_groups_minus1 + 1) * sizeof(uint16_t));
            for(uint32_t iGroup = 0; iGroup < pps->num_slice_groups_minus1; iGroup++) {
                node = cutDescriptor_ue(&stream, &field_top_left, nodes);
                indexFENode(node, iGroup, -1, -1);
                pps->top_left[iGroup] = node->translation.ui;
                node = cutDescriptor_ue(&stream, &field_bottom_right, nodes);
                indexFENode(node, iGroup, -1, -1);
                pps->bottom_right[iGroup] = node->translation.ui;
            }
        } else if (pps->slice_group_map_type == 3 || pps->slice_group_map_type == 4 || pps->slice_group_map_type == 5) {
            node = cutDescriptor_u(&stream, 1, &field_slice_group_change_direction_flag, nodes);
            pps->slice_group_change_direction_flag = node->translation.ui;
            node = cutDescriptor_ue(&stream, &field_slice_group_change_rate_minus1, nodes);
            pps->slice_group_change_rate_minus1 = node->translation.ui;
        } else if (pps->slice_group_map_type == 6) {
            node = cutDescriptor_ue(&stream, &field_pic_size_in_map_units_minus1, nodes);
            uint32_t pic_size_in_map_units_minus1 = node->translation.ui;
            pps->slice_group_id = (uint16_t *)malloc((pic_size_in_map_units_minus1 + 1) * sizeof(uint16_t));
            for(uint32_t i = 0; i <= pic_size_in_map_units_minus1; i++) {
                node = cutDescriptor_u(&stream, ceil(log2(pps->num_slice_groups_minus1 + 1)), &field_slice_group_id, nodes);
                indexFENode(node, i, -1, -1);
                pps->slice_group_id[i] = node->translation.ui;
            }
        }
    }

    cutDescriptor_ue(&stream, &field_num_ref_idx_l0_default_active_minus1, nodes);
    cutDescriptor_ue(&stream, &field_num_ref_idx_l1_default_active_minus1, nodes);

    node = cutDescriptor_u(&stream, 1, &field_weighted_pred_flag, nodes);
    pps->weighted_pred_flag = node->translation.ui;

    node = cutDescriptor_u(&stream, 2, &field_weighted_bipred_idc, nodes);
    pps->weighted_bipred_idc = node->translation.ui;

    cutDescriptor_se(&stream, &field_pic_init_qp_minus26, nodes);
    cutDescriptor_se(&stream, &field_pic_init_qs_minus26, nodes);
    cutDescriptor_se(&stream, &field_chroma_qp_index_offset, nodes);
    node = cutDescriptor_u(&stream, 1, &field_deblocking_filter_control_present_flag, nodes);
    pps->deblocking_filter_control_present_flag = node->translation.ui;
    cutDescriptor_u(&stream, 1, &field_constrained_intra_pred_flag, nodes);
    node = cutDescriptor_u(&stream, 1, &field_redundant_pic_cnt_present_flag, nodes);
    pps->redundant_pic_cnt_present_flag = node->translation.ui;

    FERange range_trail;
    subFERange(&range, &range_trail, bit_len - trail_bits, trail_bits);
    initBitStream(&stream, &range_trail);
    cutDescriptor_u(&stream, 1, &field_rbsp_stop_one_bit, nodes);
    if (trail_bits > 1) {
        cutDescriptor_u(&stream, trail_bits - 1, &field_rbsp_alignment_zero_bit, nodes);
    }

    pps->SliceGroupChangeRate = pps->slice_group_change_rate_minus1 + 1; //(7-23)

    if (context_h264->pps.find(pic_parameter_set_id) != context_h264->pps.end()) {
        delete pps;
    } else {
        context_h264->pps[pic_parameter_set_id] = pps;
    }
    return range.bit_len;
}

int64_t dissectSlice(FERange range, void *context, FEList *nodes){
    auto context_slice = new ContextSlice();
    context_slice->h264 = (ContextH264 *)context;

    FEFieldNode *node;
    BitStream stream;
    initBitStream(&stream, &range);

    cutDescriptor_u(&stream, 1, &field_forbidden_zero_bit, nodes);
    node = cutDescriptor_u(&stream, 2, &field_nal_ref_idc, nodes);
    context_slice->nal_ref_idc = node->translation.ui;
    node = cutDescriptor_u(&stream, 5, &field_nal_unit_type, nodes);
    context_slice->nal_unit_type = node->translation.ui;

    uint64_t len = remainFERangeByte(&range, 1);
    auto data = fetchFERangeByte(&range, 1, len);
    if (!data) {
        delete context_slice;
        return -1;
    }

    FERange sub;
    subFERangeByte(&range, &sub, 1, len);
    auto escaped = needEscape(data, len);
    node = allocFENode(nodes, &field_slice_layer_without_partitioning_rbsp, sub);
    contextFENode(node, context_slice, freeContextSlice);
    if (escaped) {
        char *rbsp = (char *)malloc(len);
        int rbsp_len = getRBSP(data, rbsp, len);
        translateFENodeText(node, rbsp, rbsp_len);
    }

    return range.bit_len;
}

int64_t dissect_slice_layer_without_partitioning_rbsp(FERange range, void *context, FEList *nodes) {
    uint64_t bit_len = remainFERange(&range, 0);
    char trail = *fetchFERangeByte(&range, (bit_len >> 3) - 1, 1);
    if (trail == 0) return -1;
    uint32_t trail_bits = log2((uint8_t)(trail & -trail)) + 1;

    FEFieldNode *node;
    FERange sub;
    subFERange(&range, &sub, 0, -1);
    node = allocFENode(nodes, &field_slice_header, sub);
    contextFENode(node, context, nullptr);

    subFERange(&range, &sub, -1, -1);
    node = allocFENode(nodes, &field_slice_data, sub);
    contextFENode(node, context, nullptr);

    BitStream stream;
    subFERange(&range, &sub, bit_len - trail_bits, trail_bits);
    initBitStream(&stream, &sub);
    cutDescriptor_u(&stream, 1, &field_rbsp_stop_one_bit, nodes);
    if (trail_bits > 1) {
        cutDescriptor_u(&stream, trail_bits - 1, &field_rbsp_alignment_zero_bit, nodes);
    }

    return bit_len;
}

int64_t dissect_ref_pic_list_mvc_modification(BitStream *stream, ContextSlice *context, FEList *nodes) {
    return 0;
}

int64_t dissect_ref_pic_list_modification(BitStream *stream, ContextSlice *context, FEList *nodes) {
    FEFieldNode *node;
    if (context->slice_type % 5 != 2 && context->slice_type % 5 != 4) {
        node = cutDescriptor_u(stream, 1, &field_ref_pic_list_modification_flag_l0, nodes);
        uint8_t ref_pic_list_modification_flag_l0 = node->translation.ui;
        if (ref_pic_list_modification_flag_l0) {
            uint8_t modification_of_pic_nums_idc;
            do {
                node = cutDescriptor_ue(stream, &field_modification_of_pic_nums_idc, nodes);
                modification_of_pic_nums_idc = node->translation.ui;
                if (modification_of_pic_nums_idc == 0 || modification_of_pic_nums_idc == 1) {
                    cutDescriptor_ue(stream, &field_abs_diff_pic_num_minus1, nodes);
                } else if(modification_of_pic_nums_idc == 2) {
                    cutDescriptor_ue(stream, &field_long_term_pic_num, nodes);
                }
            }while(modification_of_pic_nums_idc != 3);
        }
    }

    if (context->slice_type % 5 == 1) {
        node = cutDescriptor_u(stream, 1, &field_ref_pic_list_modification_flag_l1, nodes);
        uint8_t ref_pic_list_modification_flag_l1 = node->translation.ui;
        if (ref_pic_list_modification_flag_l1) {
            uint8_t modification_of_pic_nums_idc;
            do {
                node = cutDescriptor_ue(stream, &field_modification_of_pic_nums_idc, nodes);
                modification_of_pic_nums_idc = node->translation.ui;
                if (modification_of_pic_nums_idc == 0 || modification_of_pic_nums_idc == 1) {
                    cutDescriptor_ue(stream, &field_abs_diff_pic_num_minus1, nodes);
                } else if(modification_of_pic_nums_idc == 2) {
                    cutDescriptor_ue(stream, &field_long_term_pic_num, nodes);
                }
            }while(modification_of_pic_nums_idc != 3);
        }
    }

    return 0;
}

int64_t dissect_pred_weight_table(BitStream *stream, ContextSlice *context, FEList *nodes) {
    auto pps = context->h264->pps[context->pic_parameter_set_id];
    auto sps = context->h264->sps[pps->seq_parameter_set_id];
    FEFieldNode *node;

    cutDescriptor_ue(stream, &field_luma_log2_weight_denom, nodes);
    if (sps->ChromaArrayType != 0) {
        cutDescriptor_ue(stream, &field_chroma_log2_weight_denom, nodes);
    }

    for (uint32_t i = 0; i <= context->num_ref_idx_l0_active_minus1; i++) {
        node = cutDescriptor_u(stream, 1, &field_luma_weight_l0_flag, nodes);
        uint8_t luma_weight_l0_flag = node->translation.ui;
        if (luma_weight_l0_flag) {
            node = cutDescriptor_se(stream, &field_luma_weight_l0, nodes);
            indexFENode(node, i, -1, -1);
            node = cutDescriptor_se(stream, &field_luma_offset_l0, nodes);
            indexFENode(node, i, -1, -1);
        }

        if (sps->ChromaArrayType != 0) {
            node = cutDescriptor_u(stream, 1, &field_chroma_weight_l0_flag, nodes);
            uint8_t chroma_weight_l0_flag = node->translation.ui;
            if( chroma_weight_l0_flag ){
                for (uint8_t j=0; j < 2; j++) {
                    node = cutDescriptor_se(stream, &field_chroma_weight_l0, nodes);
                    indexFENode(node, i, j, -1);
                    node = cutDescriptor_se(stream, &field_chroma_offset_l0, nodes);
                    indexFENode(node, i, j, -1);
                }
            }
        }
    }

    if (context->slice_type % 5 == 1) {
        for(uint32_t i = 0; i <= context->num_ref_idx_l1_active_minus1; i++ ) {
            node = cutDescriptor_u(stream, 1, &field_luma_weight_l1_flag, nodes);
            uint8_t luma_weight_l1_flag = node->translation.ui;
            if (luma_weight_l1_flag) {
                node = cutDescriptor_se(stream, &field_luma_weight_l1, nodes);
                indexFENode(node, i, -1, -1);
                node = cutDescriptor_se(stream, &field_luma_offset_l1, nodes);
                indexFENode(node, i, -1, -1);
            }

            if (sps->ChromaArrayType != 0) {
                node = cutDescriptor_u(stream, 1, &field_chroma_weight_l1_flag, nodes);
                uint8_t chroma_weight_l1_flag = node->translation.ui;
                if (chroma_weight_l1_flag){
                    for(uint8_t j = 0; j < 2; j++ ) {
                        node = cutDescriptor_se(stream, &field_chroma_weight_l1, nodes);
                        indexFENode(node, i, j, -1);
                        node = cutDescriptor_se(stream, &field_chroma_offset_l1, nodes);
                        indexFENode(node, i, j, -1);
                    }
                }
            }
        }
    }

    return 0;
}

int64_t dissect_dec_ref_pic_marking(BitStream *stream, ContextSlice *context, FEList *nodes) {
    // auto pps = context->h264->pps[context->pic_parameter_set_id];
    // auto sps = context->h264->sps[pps->seq_parameter_set_id];
    FEFieldNode *node;
    //IdrPicFlag
    if (context->slice_type % 5 == 1) {
        cutDescriptor_u(stream, 1, &field_no_output_of_prior_pics_flag, nodes);
        cutDescriptor_u(stream, 1, &field_long_term_reference_flag, nodes);
    } else {
        node = cutDescriptor_u(stream, 1, &field_long_term_reference_flag, nodes);
        uint8_t adaptive_ref_pic_marking_mode_flag = node->translation.ui;
        if (adaptive_ref_pic_marking_mode_flag) {
            uint8_t memory_management_control_operation;
            do {
                node = cutDescriptor_ue(stream, &field_memory_management_control_operation, nodes);
                memory_management_control_operation = node->translation.ui;
                if (memory_management_control_operation == 1 || memory_management_control_operation == 3)
                    cutDescriptor_ue(stream, &field_difference_of_pic_nums_minus1, nodes);
                if (memory_management_control_operation == 2)
                    cutDescriptor_ue(stream, &field_long_term_pic_num, nodes);
                if (memory_management_control_operation == 3 || memory_management_control_operation == 6)
                    cutDescriptor_ue(stream, &field_long_term_frame_idx, nodes);
                if (memory_management_control_operation == 4)
                    cutDescriptor_ue(stream, &field_max_long_term_frame_idx_plus1, nodes);
            } while(memory_management_control_operation != 0);
        }
    }
    return 0;
}

void derive_mapUnitToSliceGroupMap(ContextSlice *slice){
    ContextPPS *pps = slice->h264->pps[slice->pic_parameter_set_id];
    ContextSPS *sps = slice->h264->sps[pps->seq_parameter_set_id];

    slice->mapUnitToSliceGroupMap = (uint16_t *)malloc(sps->PicSizeInMapUnits * sizeof(uint16_t));
    if (pps->num_slice_groups_minus1 == 0) {
        memset(slice->mapUnitToSliceGroupMap, 0, sps->PicSizeInMapUnits * sizeof(uint16_t)); //(8-15)
        return;
    }

    if (pps->slice_group_map_type == 0) {//(8-17)
        uint32_t i = 0;
        do {
            for(uint32_t iGroup = 0; iGroup <= pps->num_slice_groups_minus1 && i < sps->PicSizeInMapUnits; i += pps->run_length_minus1[iGroup++]+1)
                for(uint32_t j = 0; j <= pps->run_length_minus1[iGroup] && i + j < sps->PicSizeInMapUnits; j++ )
                    slice->mapUnitToSliceGroupMap[i + j] = iGroup;
        } while(i < sps->PicSizeInMapUnits);
    } else if (pps->slice_group_map_type == 1) {//(8-18)
        for (uint32_t i = 0; i < sps->PicSizeInMapUnits; i++ )
            slice->mapUnitToSliceGroupMap[i] = ((i%sps->PicWidthInMbs) + (((i/sps->PicWidthInMbs) * (pps->num_slice_groups_minus1 + 1))/ 2)) % (pps->num_slice_groups_minus1 + 1);
    } else if (pps->slice_group_map_type == 2) {//(8-19)
        for (uint32_t i = 0; i < sps->PicSizeInMapUnits; i++)
            slice->mapUnitToSliceGroupMap[i] = pps->num_slice_groups_minus1;

        for(uint32_t iGroup = pps->num_slice_groups_minus1 - 1; iGroup >= 0; iGroup--) {
            uint32_t yTopLeft = pps->top_left[iGroup] / sps->PicWidthInMbs;
            uint32_t xTopLeft = pps->top_left[iGroup] % sps->PicWidthInMbs;
            uint32_t yBottomRight = pps->bottom_right[iGroup] / sps->PicWidthInMbs;
            uint32_t xBottomRight = pps->bottom_right[iGroup] % sps->PicWidthInMbs;
            for(uint32_t y = yTopLeft; y <= yBottomRight; y++ )
                for(uint32_t x = xTopLeft; x <= xBottomRight; x++ )
                    slice->mapUnitToSliceGroupMap[y * sps->PicWidthInMbs + x] = iGroup;
        }
    } else if (pps->slice_group_map_type == 3) {//(8-20)
        for(int32_t i = 0; i < sps->PicSizeInMapUnits; i++)
            slice->mapUnitToSliceGroupMap[i] = 1;

        uint32_t x = (sps->PicWidthInMbs - pps->slice_group_change_direction_flag )/2;
        uint32_t y = (sps->PicHeightInMapUnits - pps->slice_group_change_direction_flag )/2;
        uint32_t leftBound = x, topBound = y;
        uint32_t rightBound = x, bottomBound = y;
        uint32_t xDir = pps->slice_group_change_direction_flag - 1,  yDir = pps->slice_group_change_direction_flag;
        uint8_t mapUnitVacant = 0;
        for (uint32_t k = 0; k < slice->MapUnitsInSliceGroup0; k += mapUnitVacant) {
            mapUnitVacant = slice->mapUnitToSliceGroupMap[y * sps->PicWidthInMbs + x] == 1;
            if (mapUnitVacant)
                slice->mapUnitToSliceGroupMap[y * sps->PicWidthInMbs + x] = 0;
            if (xDir == -1 && x == leftBound ) {
                leftBound = qMax(leftBound - 1, (uint32_t)0);
                x = leftBound;
                xDir = 0;
                yDir = 2 * pps->slice_group_change_direction_flag -  1;
            } else if( xDir == 1 && x == rightBound ) {
                rightBound = qMin(rightBound + 1, sps->PicWidthInMbs - 1);
                x = rightBound;
                xDir = 0;
                yDir = 1 - 2 * pps->slice_group_change_direction_flag;
            } else if( yDir == -1 && y == topBound ) {
                topBound = qMax(topBound - 1, (uint32_t)0);
                y = topBound;
                xDir = 1 - 2 * pps->slice_group_change_direction_flag;
                yDir = 0;
            } else if( yDir == 1 && y == bottomBound ) {
                bottomBound = qMin(bottomBound + 1, sps->PicHeightInMapUnits - 1);
                y = bottomBound;
                xDir = 2 * pps->slice_group_change_direction_flag - 1;
                yDir = 0;
            } else {
                x = x + xDir;
                y = y + yDir;
            }
        }
    } else if (pps->slice_group_map_type == 4) {//(8-21)
        for (uint32_t i = 0; i < sps->PicSizeInMapUnits; i++)
            if (i < slice->sizeOfUpperLeftGroup)
                slice->mapUnitToSliceGroupMap[i] = pps->slice_group_change_direction_flag;
            else
                slice->mapUnitToSliceGroupMap[i] = 1 - pps->slice_group_change_direction_flag;
    } else if (pps->slice_group_map_type == 5) {//(8-22)
        uint32_t k = 0;
        for (uint32_t j = 0; j < sps->PicWidthInMbs; j++)
            for (uint32_t i = 0; i < sps->PicHeightInMapUnits; i++)
                if (k++ < slice->sizeOfUpperLeftGroup)
                    slice->mapUnitToSliceGroupMap[i * sps->PicWidthInMbs + j] = pps->slice_group_change_direction_flag;
                else
                    slice->mapUnitToSliceGroupMap[i * sps->PicWidthInMbs + j] = 1 - pps->slice_group_change_direction_flag;
    } else if (pps->slice_group_map_type == 6) {//(8-23)
        for (uint32_t i = 0; i < sps->PicSizeInMapUnits; i++)
            slice->mapUnitToSliceGroupMap[i] = pps->slice_group_id[i];
    }
    return;
}

void derive_MbToSliceGroupMap(ContextSlice *slice){
    ContextPPS *pps = slice->h264->pps[slice->pic_parameter_set_id];
    ContextSPS *sps = slice->h264->sps[pps->seq_parameter_set_id];

    slice->MbToSliceGroupMap = (uint16_t *)malloc(sps->PicSizeInMapUnits * sizeof(uint16_t));
    if (sps->frame_mbs_only_flag == 1 || slice->field_pic_flag == 1) {
        for (uint32_t i = 0; i < sps->PicSizeInMapUnits; i++)
            slice->MbToSliceGroupMap[i] = slice->mapUnitToSliceGroupMap[i]; //(8-24)
    } else if (slice->MbaffFrameFlag == 1){
        for (uint32_t i = 0; i < sps->PicSizeInMapUnits; i++)
            slice->MbToSliceGroupMap[i] = slice->mapUnitToSliceGroupMap[i/2]; //(8-25)
    } else {
        for (uint32_t i = 0; i < sps->PicSizeInMapUnits; i++)
            slice->MbToSliceGroupMap[i] = slice->mapUnitToSliceGroupMap[(i/(2 * sps->PicWidthInMbs )) * sps->PicWidthInMbs+ (i%sps->PicWidthInMbs)]; //(8-26)
    }
}

int64_t dissect_slice_header(FERange range, void *context, FEList *nodes) {
    auto slice = (ContextSlice *)context;

    FERange sub;
    FEFieldNode *node;
    BitStream stream;
    initBitStream(&stream, &range);
    node = cutDescriptor_ue(&stream, &field_first_mb_in_slice, nodes);
    slice->first_mb_in_slice = node->translation.ui;
    node = cutDescriptor_ue(&stream, &field_slice_type, nodes);
    slice->slice_type = node->translation.ui;
    node = cutDescriptor_ue(&stream, &field_pic_parameter_set_id, nodes);
    slice->pic_parameter_set_id = node->translation.ui;

    auto it_pps = slice->h264->pps.find(slice->pic_parameter_set_id);
    if (it_pps == slice->h264->pps.end()) return 0;
    auto pps = it_pps->second;
    auto it_sps = slice->h264->sps.find(pps->seq_parameter_set_id);
    if (it_sps == slice->h264->sps.end()) return 0;
    auto sps = it_sps->second;

    if (sps->separate_colour_plane_flag)
        cutDescriptor_u(&stream, 2, &field_colour_plane_id, nodes);
    cutDescriptor_u(&stream, sps->log2_max_frame_num_minus4 + 4, &field_frame_num, nodes);
    if (!sps->frame_mbs_only_flag) {
        node = cutDescriptor_u(&stream, 1, &field_field_pic_flag, nodes);
        slice->field_pic_flag = node->translation.ui;
        if (slice->field_pic_flag) {
            cutDescriptor_u(&stream, 1, &field_bottom_field_flag, nodes);
        }
    }

    //IdrPicFlag
    if (slice->slice_type % 5 == 1) {
        cutDescriptor_ue(&stream, &field_idr_pic_id, nodes);
    }

    if (sps->pic_order_cnt_type == 0) {
        cutDescriptor_u(&stream, sps->log2_max_pic_order_cnt_lsb_minus4 + 4, &field_pic_order_cnt_lsb, nodes);
        if (pps->bottom_field_pic_order_in_frame_present_flag && !slice->field_pic_flag) {
            cutDescriptor_se(&stream, &field_delta_pic_order_cnt_bottom, nodes);
        }
    }

    if (sps->pic_order_cnt_type == 1 && !sps->delta_pic_order_always_zero_flag) {
        node = cutDescriptor_se(&stream, &field_delta_pic_order_cnt, nodes);
        indexFENode(node, 0, -1, -1);
        if (pps->bottom_field_pic_order_in_frame_present_flag && !slice->field_pic_flag ) {
            node = cutDescriptor_se(&stream, &field_delta_pic_order_cnt, nodes);
            indexFENode(node, 1, -1, -1);
        }
    }

    if (pps->redundant_pic_cnt_present_flag) {
        cutDescriptor_ue(&stream, &field_redundant_pic_cnt, nodes);
    }

    if (slice->slice_type % 5 == 1) //B
        cutDescriptor_u(&stream, 1, &field_direct_spatial_mv_pred_flag, nodes);

    if (slice->slice_type % 5 == 0 || slice->slice_type % 5 == 3 || slice->slice_type % 5 == 1) {//P,SP,B
        node = cutDescriptor_u(&stream, 1, &field_num_ref_idx_active_override_flag, nodes);
        uint8_t num_ref_idx_active_override_flag = node->translation.ui;
        if (num_ref_idx_active_override_flag) {
            node = cutDescriptor_ue(&stream, &field_num_ref_idx_l0_active_minus1, nodes);
            slice->num_ref_idx_l0_active_minus1 = node->translation.ui;
            if (slice->slice_type % 5 == 1) {
                node = cutDescriptor_ue(&stream, &field_num_ref_idx_l1_active_minus1, nodes);
                slice->num_ref_idx_l1_active_minus1 = node->translation.ui;
            }
        }
    }

    subFERange(stream.range, &sub, stream.bit_current, -1);
    if (slice->nal_unit_type == 20 || slice->nal_unit_type == 21) {
        allocFENode(nodes, &field_ref_pic_list_mvc_modification, sub);
        pushBitStream(&stream);
        /* specified in Annex H */
        dissect_ref_pic_list_mvc_modification(&stream, slice, nodes);
    } else {
        allocFENode(nodes, &field_ref_pic_list_modification, sub);
        pushBitStream(&stream);
        dissect_ref_pic_list_modification(&stream, slice, nodes);
    }
    popBitStream(&stream);

    if((pps->weighted_pred_flag && (slice->slice_type % 5 == 0 || slice->slice_type % 5 == 3)) ||
        (pps->weighted_bipred_idc == 1 && slice->slice_type % 5 == 1)) {
        subFERange(stream.range, &sub, stream.bit_current, -1);
        allocFENode(nodes, &field_pred_weight_table, sub);
        pushBitStream(&stream);
        dissect_pred_weight_table(&stream, slice, nodes);
        popBitStream(&stream);
    }

    if (slice->nal_ref_idc != 0) {
        subFERange(stream.range, &sub, stream.bit_current, -1);
        allocFENode(nodes, &field_dec_ref_pic_marking, sub);
        pushBitStream(&stream);
        dissect_dec_ref_pic_marking(&stream, slice, nodes);
        popBitStream(&stream);
    }

    if (pps->entropy_coding_mode_flag && slice->slice_type % 5 != 2 && slice->slice_type % 5 != 4)
        cutDescriptor_ue(&stream, &field_cabac_init_idc, nodes);

    cutDescriptor_se(&stream, &field_slice_qp_delta, nodes);

    if (slice->slice_type % 5 == 3 || slice->slice_type % 5 == 4) {
        if (slice->slice_type % 5 == 3)
            cutDescriptor_u(&stream, 1, &field_sp_for_switch_flag, nodes);
        cutDescriptor_se(&stream, &field_slice_qs_delta, nodes);
    }

    if (pps->deblocking_filter_control_present_flag) {
        node = cutDescriptor_ue(&stream, &field_disable_deblocking_filter_idc, nodes);
        uint8_t disable_deblocking_filter_idc = node->translation.ui;
        if (disable_deblocking_filter_idc != 1) {
            cutDescriptor_se(&stream, &field_slice_alpha_c0_offset_div2, nodes);
            cutDescriptor_se(&stream, &field_slice_beta_offset_div2, nodes);
        }
    }

    if (pps->num_slice_groups_minus1 > 0 && pps->slice_group_map_type >= 3 && pps->slice_group_map_type <= 5) {
        uint8_t v = ceil(log2(sps->PicSizeInMapUnits/pps->SliceGroupChangeRate + 1));
        node = cutDescriptor_u(&stream, v, &field_slice_group_change_cycle, nodes);
        slice->slice_group_change_cycle = node->translation.ui;
    }

    slice->PicHeightInMbs = sps->FrameHeightInMbs / (1 + slice->field_pic_flag); //(7-26)
    slice->PicSizeInMbs = sps->PicWidthInMbs * slice->PicHeightInMbs;//(7-29)
    slice->MbaffFrameFlag = (sps->mb_adaptive_frame_field_flag && !slice->field_pic_flag); //7-25
    slice->MapUnitsInSliceGroup0 = qMin(slice->slice_group_change_cycle * pps->SliceGroupChangeRate, sps->PicSizeInMapUnits ); //(7-34)
    slice->sizeOfUpperLeftGroup = pps->slice_group_change_direction_flag ? sps->PicSizeInMapUnits - slice->MapUnitsInSliceGroup0 : slice->MapUnitsInSliceGroup0; // (8-14)
    derive_mapUnitToSliceGroupMap(slice);
    derive_MbToSliceGroupMap(slice);

    return offsetBitStream(&stream);
}

//8-16
uint32_t NextMbAddress(ContextSlice *slice, uint32_t n){
    // auto pps = slice->h264->pps[slice->pic_parameter_set_id];
    // auto sps = slice->h264->sps[pps->seq_parameter_set_id];

    uint32_t i = n + 1;
    while (i < slice->PicSizeInMbs && slice->MbToSliceGroupMap[i] != slice->MbToSliceGroupMap[n])
        i++;
    return i;
}

int64_t dissect_macroblock_layer(){
    return 0;
}

int64_t dissect_slice_data(FERange range, void *context, FEList *nodes) {
    BitStream stream;
    FEFieldNode *node;
    initBitStream(&stream, &range);
    auto slice = (ContextSlice *)context;
    auto pps = slice->h264->pps[slice->pic_parameter_set_id];
    auto sps = slice->h264->sps[pps->seq_parameter_set_id];

    if (pps->entropy_coding_mode_flag) {
        cutDescriptor_align(&stream, &field_cabac_alignment_one_bit, nodes);
    }

    uint32_t CurrMbAddr = slice->first_mb_in_slice * (1 + slice->MbaffFrameFlag);
    uint8_t moreDataFlag = 1;
    uint8_t prevMbSkipped = 0;
    uint8_t mb_skip_flag = 0;
    do {
        if (slice->slice_type % 5 != 2 && slice->slice_type % 5 != 4){ // !I && !SI
            if (!pps->entropy_coding_mode_flag) {
                node = cutDescriptor_ue(&stream, &field_mb_skip_run, nodes);
                uint32_t mb_skip_run = node->translation.ui;
                prevMbSkipped = mb_skip_run > 0;
                for (uint32_t i = 0; i < mb_skip_run; i++)
                    CurrMbAddr = NextMbAddress(slice, CurrMbAddr);
                if (mb_skip_run > 0)
                    moreDataFlag = more_rbsp_data(&stream);
            } else {
                // node = cutDescriptor_ae(&stream, &field_mb_skip_flag, nodes);
                mb_skip_flag = node->translation.ui;
                moreDataFlag = !mb_skip_flag;
            }
        }

        if (moreDataFlag) {
            if( slice->MbaffFrameFlag && (CurrMbAddr % 2 == 0 || (CurrMbAddr % 2 == 1 && prevMbSkipped)))
                if(!pps->entropy_coding_mode_flag) {
                    node = cutDescriptor_u(&stream, 1, &field_mb_field_decoding_flag, nodes);
                } else {
                    // node = cutDescriptor_ae(&stream, &field_mb_field_decoding_flag, nodes);
                }

            dissect_macroblock_layer();
        }

        if (!pps->entropy_coding_mode_flag)
            moreDataFlag = more_rbsp_data(&stream);
        else {
            if(slice->slice_type % 5 != 2 && slice->slice_type % 5 != 4)  // !I && !SI
                prevMbSkipped = mb_skip_flag;
            if(slice->MbaffFrameFlag && CurrMbAddr % 2 == 0)
                moreDataFlag = 1;
            else {
                // node = cutDescriptor_ae(&stream, &field_end_of_slice_flag, nodes);
                uint8_t end_of_slice_flag = node->translation.ui;
                moreDataFlag = !end_of_slice_flag;
            }
        }
        CurrMbAddr = NextMbAddress(slice, CurrMbAddr);
    } while(moreDataFlag);
    return offsetBitStream(&stream);
}

int display_slice_type(FEFieldNode *node, char *string, int len) {
    const char *slice_type_strings[] = {"P", "B", "I", "SP", "SI", "P", "B", "I", "SP", "SI", "Unknown"};
    return sprintf(string, "%s(%d)", slice_type_strings[node->translation.ui > 10 ? 10 : node->translation.ui], node->translation.ui);
}
